package com.system.demo.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.system.demo.commonService.RedisService;
import com.system.demo.entity.DTO.NoticeSearchDTO;
import com.system.demo.entity.database.*;
import com.system.demo.mapper.*;
import com.system.demo.service.IssueNoticeService;
import com.system.demo.tool.ResponseResult;
import com.system.demo.utils.MinioUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.system.demo.service.constant.ApplicationStatus.SUBMITTED;
import static com.system.demo.service.constant.PaperConstant.MINIO_NOTICE_ATTACHMENT_PATH;
import static org.apache.commons.lang3.StringUtils.substring;

@Service
public class IssueNoticeServiceImpl implements IssueNoticeService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    NoticeMapper noticeMapper;

    @Autowired
    AttachmentMapper attachmentMapper;

    @Autowired
    NoticeApplicationMapper applicationMapper;

    @Value("${myIp.ip}")
    private String ip;

    @Value("${minio.port}")
    private int port;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Autowired
    private MinioUtils minioUtils;
    @Autowired
    private NoticeApplicationMapper noticeApplicationMapper;
    @Autowired
    private StudentMapper studentMapper;

    /**
     * 管理员发布通知
     *
     * @param title
     * @param deadLine
     * @param file        通知文件
     * @param attachments 附件
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<?> IssueNotice(String title, LocalDateTime deadLine, MultipartFile file, List<MultipartFile> attachments){
        try{
            System.out.println(deadLine);
            // 作者？ 发布时间？ 浏览次数？
            NoticeMainFile noticeMainFile = new NoticeMainFile();
            // 对title进行判重
            QueryWrapper<NoticeMainFile> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("title", title);
            NoticeMainFile noticeMainFile1 = noticeMapper.selectOne(queryWrapper1);
            if (noticeMainFile1 != null){
                return ResponseResult.Conflict("数据库中已存在同名通知");
            }
            noticeMainFile.setTitle(title);
            noticeMainFile.setFilename(file.getOriginalFilename());

            // 按照登陆人的账号查找登陆人姓名
            String Uid = StpUtil.getLoginId().toString();
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("uid", Uid);
            User user = userMapper.selectOne(queryWrapper);

            noticeMainFile.setAuthor(user.getUsername());

            // 将文件插入到minio中并设置url
            // 生成文件的完整路径  public/notice/通知名/通知本体文件 + 附件文件夹/附件
            String path = "notice/" + title;
            String objectName = file.getOriginalFilename();
            String fileUrl = "http://" + ip + ":" + port + "/" + bucketName + "/" + path + "/" + objectName;

            boolean uploadSuccess = minioUtils.uploadFile(file, bucketName, path, objectName);
            if (!uploadSuccess) {
                return ResponseResult.InternalServerError("Minio文件上传失败");
            }


            //return ResponseResult.success("文件上传成功");
            noticeMainFile.setNoticeFileUrl(fileUrl);
            noticeMainFile.setCreateTime(LocalDateTime.now());
            noticeMainFile.setDeadLine(deadLine);
            noticeMainFile.setFileCount(0);
            noticeMainFile.setViewCount(0);
            // 通知文件上传
            if(noticeMapper.insert(noticeMainFile) > 0){
                System.out.println("通知文件上传成功");
            }
            else return ResponseResult.InternalServerError("通知文件上传失败");

            // 附件
            if (attachments.isEmpty()){
                return ResponseResult.success("文件上传成功");
            }
            for (MultipartFile attachment : attachments) {
                if (attachment.isEmpty()){
                    continue;
                }
                NoticeAttachment noticeAttachment = new NoticeAttachment();

                noticeAttachment.setNoticeId(noticeMainFile.getId());
                noticeAttachment.setTitle(attachment.getOriginalFilename());

                //url
                // 将文件插入到minio中并设置url
                // 生成文件的完整路径  public/notice/通知名/通知本体文件 + 附件文件夹/附件
                path = "notice/" + title + "/attachment";
                objectName = attachment.getOriginalFilename();
                String Url = "http://" + ip + ":" + port + "/" + bucketName + "/" + path + "/" + objectName;

                boolean uploadAttachmentSuccess = minioUtils.uploadFile(attachment, bucketName, path, objectName);
                if (!uploadAttachmentSuccess) {
                    return ResponseResult.InternalServerError("Minio文件上传失败");
                }

                noticeAttachment.setUrl(Url);
                noticeAttachment.setDownload(0);

                noticeMainFile.setFileCount(attachments.size());
                noticeMapper.updateById(noticeMainFile);
                attachmentMapper.insert(noticeAttachment);
            }
            return ResponseResult.success("文件上传成功");
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<?> deleteNotice(List<Integer> tableIds) {
        //删除数据库中的记录，删除minio中的文件
        try{
            // 找notice_attachment中跟id相符的，删minio，然后删表记录，再删notice_file中的minio，然后删表记录
            // 先找id相同的url
            String value =  "(" + String.join(", ", tableIds.stream().map(String::valueOf).toArray(String[]::new)) + ")";
            List<Integer> attachmentIds = attachmentMapper.selectAttachmentsByNoticeIds(value);
            if (!attachmentIds.isEmpty()) {
                attachmentMapper.deleteBatchIds(attachmentIds);
            }
            for (Integer tableId : tableIds) {
                LambdaQueryWrapper<NoticeMainFile> queryWrapper1 = new LambdaQueryWrapper<>();
                queryWrapper1.eq(NoticeMainFile::getId, tableId);
                NoticeMainFile noticeMainFile1 = noticeMapper.selectOne(queryWrapper1);
                String path = "notice/" + noticeMainFile1.getTitle();
                boolean b = minioUtils.deleteFolder(bucketName, path);
                if (!b){
                    return ResponseResult.InternalServerError("Minio寄了");
                }
            }
            noticeMapper.deleteBatchIds(tableIds);
            return ResponseResult.success("通知文件批量删除成功");
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }
    }

    @Override
    public void DownloadAttachment(Integer tableId, HttpServletResponse response) {
        try{
            LambdaQueryWrapper<NoticeAttachment> queryWrapper = Wrappers.lambdaQuery(NoticeAttachment.class)
                    .eq(NoticeAttachment::getNoticeId, tableId)
                    .select(NoticeAttachment::getUrl);
            List<String> fileUrl = attachmentMapper.selectList(queryWrapper).stream().map(NoticeAttachment::getUrl).collect(Collectors.toList());

            LambdaQueryWrapper<NoticeMainFile> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(NoticeMainFile::getId, tableId);
            NoticeMainFile noticeMainFile = noticeMapper.selectOne(queryWrapper1);

            String title = noticeMainFile.getTitle();

            List<String> fileUrlList = new ArrayList<>();

            for (String file : fileUrl) {
                String name = file.substring(file.lastIndexOf("/") + 1);
                String url = "notice/" +  title + "/attachment/" + name;
                fileUrlList.add(url);
            }

            minioUtils.ZipMultiFileToMinIO(response, bucketName, fileUrlList,title);

        }
        catch (Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public ResponseResult<?> SumbitApplication(MultipartFile file, Integer noticeId) {
        try{
            String Uid = StpUtil.getLoginId().toString();

            NoticeApplication noticeApplication = new NoticeApplication();


            noticeApplication.setNoticeId(noticeId);
            noticeApplication.setUid(Uid);
            noticeApplication.setCreateTime(LocalDateTime.now());
            noticeApplication.setStatus(SUBMITTED); // 状态只有已提交和已审核两种状态

            // 查询数据库中已有的文件记录
            LambdaQueryWrapper<NoticeApplication> wrapper = Wrappers.lambdaQuery(NoticeApplication.class)
                    .eq(NoticeApplication::getNoticeId, noticeId)
                    .eq(NoticeApplication::getUid, Uid);
            NoticeApplication existNoticeApplication = noticeApplicationMapper.selectOne(wrapper);


            LambdaQueryWrapper<NoticeMainFile> noticeMainFileLambdaQueryWrapper = Wrappers.lambdaQuery(NoticeMainFile.class)
                    .eq(NoticeMainFile::getId,noticeId);
            NoticeMainFile noticeMainFile = noticeMapper.selectOne(noticeMainFileLambdaQueryWrapper);

            noticeApplication.setNoticeTitle(noticeMainFile.getTitle());
            noticeApplication.setDeadLine(noticeMainFile.getDeadLine());

            LambdaQueryWrapper<Student> userLambdaQueryWrapper = Wrappers.lambdaQuery(Student.class).eq(Student::getUid,Uid);
            Student student = studentMapper.selectOne(userLambdaQueryWrapper);

            if (existNoticeApplication != null) {
                if (!existNoticeApplication.getUid().equals(Uid) || existNoticeApplication.getStatus() == 1) {
                    return ResponseResult.Unauthorized("无操作权限");
                }
                LocalDateTime deadline = noticeMainFile.getDeadLine();
                if (LocalDateTime.now().isAfter(deadline)) {
                    if (existNoticeApplication.getStatus() == 0) {
                        return ResponseResult.Unauthorized("已经过了截止时间了");
                    }
                }
            }


            noticeApplication.setStuName(student.getStudentName());
            noticeApplication.setStuClass(student.getStudentClass());

            String ExtensionName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") );

            String UserObjectName = "(" + student.getStudentClass() + student.getStudentName() + ")" + noticeMainFile.getTitle() + ExtensionName;

            if (existNoticeApplication != null){
                if (existNoticeApplication.getUrl() != null && !existNoticeApplication.getUrl().isEmpty()) {

                    // 确保路径是从桶根目录开始的
                    String extensionName =  existNoticeApplication.getUrl().substring(existNoticeApplication.getUrl().lastIndexOf(".") );
                    String userObjectName = "(" + student.getStudentClass() + student.getStudentName() + ")" + noticeMainFile.getTitle() + extensionName;
                    String bucketPath = Uid + "/" + MINIO_NOTICE_ATTACHMENT_PATH + "/" + noticeMainFile.getTitle() + "/" + userObjectName;
                    System.out.println(bucketPath);
                    boolean deleteSuccess = minioUtils.deleteFile(bucketName, bucketPath);
                    if (!deleteSuccess) {
                        return ResponseResult.InternalServerError("Minio删除旧文件失败");
                    }

                    // 更新现有记录
                    existNoticeApplication.setUrl(null); // 清空旧文件URL

                    // 上传文件到 Minio
                    String path = Uid + "/" + MINIO_NOTICE_ATTACHMENT_PATH + "/" + noticeMainFile.getTitle();

                    boolean uploadSuccess = minioUtils.uploadFile(file, bucketName, path, UserObjectName);
                    if (!uploadSuccess) {
                        return ResponseResult.InternalServerError("Minio文件上传失败");
                    }

                    // 生成文件的完整路径
                    String fileUrl = "http://" + ip + ":" + port + "/" + bucketName + "/" + path + "/" + UserObjectName;

                    // 更新新的 PaperEvidence 对象
                    existNoticeApplication.setUrl(fileUrl);
                    existNoticeApplication.setCreateTime(LocalDateTime.now());
                    existNoticeApplication.setStatus(SUBMITTED);

                    if (existNoticeApplication.getRejectImage() != null && !existNoticeApplication.getRejectImage().isEmpty() ){
                        // 确保路径是从桶根目录开始的
                        String existName =  existNoticeApplication.getRejectImage().substring(existNoticeApplication.getRejectImage().lastIndexOf("/") );
                        String bucketPath1 = existNoticeApplication.getUid() + "/" + MINIO_NOTICE_ATTACHMENT_PATH + "/" + existNoticeApplication.getNoticeTitle() + "/" + existName;
                        System.out.println(bucketPath1);
                        boolean deleteSuccess1 = minioUtils.deleteFile(bucketName, bucketPath1);
                        if (!deleteSuccess1) {
                            return ResponseResult.InternalServerError("Minio删除旧文件失败");
                        }

                        existNoticeApplication.setRejectImage(null);
                    }

                    if (existNoticeApplication.getRejectReason() != null){
                        existNoticeApplication.setRejectReason(null);
                    }

                    if (!(noticeApplicationMapper.updateById(existNoticeApplication) > 0)) {
                        throw new RuntimeException("更新申请状态失败");
                    }
                    return ResponseResult.success("上传申请成功 ");

                }
            }

            // 上传文件到 Minio
            String path = Uid + "/" + MINIO_NOTICE_ATTACHMENT_PATH + "/" + noticeMainFile.getTitle();
            boolean uploadSuccess = minioUtils.uploadFile(file, bucketName, path, UserObjectName);
            if (!uploadSuccess) {
                return ResponseResult.InternalServerError("Minio文件上传失败");
            }

            // 生成文件的完整路径
            String fileUrl = "http://" + ip + ":" + port + "/" + bucketName + "/" + path + "/" + UserObjectName;

            // 更新新的 PaperEvidence 对象
            noticeApplication.setUrl(fileUrl);

            if (!(noticeApplicationMapper.insert(noticeApplication) > 0)) {
                throw new RuntimeException("添加申请状态失败");
            }
            return ResponseResult.success("上传申请成功 ");
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }
    }

    @Override
    public void ExportAttachment(HttpServletResponse response, List<Integer> ids) {
        try{
            LambdaQueryWrapper<NoticeApplication> wrapper = Wrappers.lambdaQuery();
            System.out.println(ids);
            if (ids != null && !ids.isEmpty()) {
                wrapper.in(NoticeApplication::getId, ids);
                List<NoticeApplication> noticeApplications = noticeApplicationMapper.selectList(wrapper);

                List<String> fileUrlList = new ArrayList<>();

                for (NoticeApplication noticeApplication : noticeApplications) {
                    LambdaQueryWrapper<NoticeMainFile> noticeMainFileLambdaQueryWrapper = Wrappers.lambdaQuery(NoticeMainFile.class).eq(NoticeMainFile::getId,noticeApplication.getNoticeId());
                    NoticeMainFile noticeMainFile = noticeMapper.selectOne(noticeMainFileLambdaQueryWrapper);
                    String title = noticeMainFile.getTitle();

                    String name = noticeApplication.getUrl().substring(noticeApplication.getUrl().lastIndexOf("/") + 1);
                    String Uid = noticeApplication.getUid();
                    String url = Uid + "/" + "notice" + "/" + title + "/" + name;
                    System.out.println(url);
                    fileUrlList.add(url);
                }

                minioUtils.ZipMultiFileToMinIO(response, bucketName, fileUrlList,"title");
            }
            else{
                throw new RuntimeException("什么都没传");
            }
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public ResponseResult<?> GetNotice(Integer current,Integer size) {
        try{
            LambdaQueryWrapper<NoticeMainFile> queryWrapper = Wrappers.lambdaQuery();

            Page<NoticeMainFile> page = new Page<>(current, size);

            Page<NoticeMainFile> result = noticeMapper.selectPage(page, queryWrapper);

            return ResponseResult.success("筛选成功",result.getTotal(),result.getRecords());
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }

    }

    @Override
    public ResponseResult<?> GetAttachments(Integer tableId) {
        try{
            LambdaQueryWrapper<NoticeAttachment> queryWrapper = Wrappers.lambdaQuery(NoticeAttachment.class).eq(NoticeAttachment::getNoticeId, tableId);
            List<NoticeAttachment> attachments = attachmentMapper.selectList(queryWrapper);
            return ResponseResult.success("查询成功",attachments);
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }
    }

    @Override
    public ResponseResult<?> SearchApplication(NoticeSearchDTO noticeSearchDTO, Integer current, Integer size) {
        try{
            if (noticeSearchDTO.getTitle() != null && noticeSearchDTO.getTitle().isEmpty()){
                noticeSearchDTO.setTitle(null);
            }

            if (noticeSearchDTO.getStudentName() != null && noticeSearchDTO.getStudentName().isEmpty()){
                noticeSearchDTO.setStudentName(null);
            }

            if (noticeSearchDTO.getStudentClass() != null && noticeSearchDTO.getStudentClass().isEmpty()){
                noticeSearchDTO.setStudentClass(null);
            }

            LambdaQueryWrapper<NoticeApplication> queryWrapper = Wrappers.lambdaQuery();

            if (noticeSearchDTO.getStatus() != null){
                queryWrapper.eq(NoticeApplication::getStatus, noticeSearchDTO.getStatus());
            }

            if (noticeSearchDTO.getStudentClass() != null){
                queryWrapper.like(NoticeApplication::getStuClass,noticeSearchDTO.getStudentClass());
            }

            if (noticeSearchDTO.getStudentName() != null){
                queryWrapper.like(NoticeApplication::getStuName,noticeSearchDTO.getStudentName());
            }

            if (noticeSearchDTO.getTitle() != null){
                queryWrapper.like(NoticeApplication::getNoticeTitle,noticeSearchDTO.getTitle());
            }

            Page<NoticeApplication> page = new Page<>(current, size);
            Page<NoticeApplication> result = noticeApplicationMapper.selectPage(page, queryWrapper);

            return ResponseResult.success("查询成功",result.getTotal(),result.getRecords());
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }

    }

    @Override
    public ResponseResult<?> GetApplicationAttachment(Integer applicationId) {
        try{
            LambdaQueryWrapper<NoticeApplication> queryWrapper = Wrappers.lambdaQuery(NoticeApplication.class).eq(NoticeApplication::getId, applicationId);
            NoticeApplication application = applicationMapper.selectOne(queryWrapper);
            return ResponseResult.success("成功查询",application);
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }

    }

    @Override
    public ResponseResult<?> Determine(Integer applicationId, String isPass, String reason, MultipartFile reasonImg) {
        try{
            LambdaQueryWrapper<NoticeApplication> queryWrapper = Wrappers.lambdaQuery(NoticeApplication.class).eq(NoticeApplication::getId, applicationId);
            NoticeApplication application = applicationMapper.selectOne(queryWrapper);
//            System.out.println(application);
            List<String> role = StpUtil.getRoleList();
//            System.out.println(role);
            Boolean flag = false;
            for (String roleName : role) {
                System.out.println(roleName);
                if (roleName.contains("ROLE_ADMIN"))flag = true;
            }
            System.out.println(flag);
            if (application.getStatus() != 0 && !flag){
                return ResponseResult.Unauthorized("没有修改权限");
            }

            if (isPass.equals("false")){
                application.setStatus(2);
                if (application.getRejectImage() != null && !application.getRejectImage().isEmpty() ){
                    // 确保路径是从桶根目录开始的
                    String existName =  application.getRejectImage().substring(application.getRejectImage().lastIndexOf("/") );
                    String bucketPath = application.getUid() + "/" + MINIO_NOTICE_ATTACHMENT_PATH + "/" + application.getNoticeTitle() + "/" + existName;
                    System.out.println(bucketPath);
                    boolean deleteSuccess = minioUtils.deleteFile(bucketName, bucketPath);
                    if (!deleteSuccess) {
                        return ResponseResult.InternalServerError("Minio删除旧文件失败");
                    }

                    application.setRejectImage(null);
                }

                if (application.getRejectReason() != null){
                    application.setRejectReason(null);
                }

                if(reason != null && !reason.isEmpty()){
                    application.setRejectReason(reason);
                }

                if(reasonImg != null && !reasonImg.isEmpty()){
                    String objectName = application.getId() + "A" + reasonImg.getOriginalFilename();
                    String path = application.getUid() + "/notice/" + application.getNoticeTitle();

                    boolean uploadSuccess = minioUtils.uploadFile(reasonImg, bucketName, path, objectName);
                    // 上传文件到 Minio
                    if (!uploadSuccess) {
                        return ResponseResult.InternalServerError("Minio文件上传失败");
                    }
                    // 生成文件的完整路径
                    String fileUrl = "http://" + ip + ":" + port + "/" + bucketName + "/" + path + "/" + objectName;
                    System.out.println(fileUrl);
                    application.setRejectImage(fileUrl);
                }

                applicationMapper.updateById(application);

                return ResponseResult.success("审核成功");
            }
            else if(isPass.equals("true")){
                application.setStatus(1);
                System.out.println(application);
                if (application.getRejectImage() != null && !application.getRejectImage().isEmpty() ){
                    // 确保路径是从桶根目录开始的
                    String existName =  application.getRejectImage().substring(application.getRejectImage().lastIndexOf("/") + 1);
                    String bucketPath = application.getUid() + "/" + MINIO_NOTICE_ATTACHMENT_PATH + "/" + application.getNoticeTitle() + "/" + existName;
                    System.out.println(bucketPath);
                    boolean deleteSuccess = minioUtils.deleteFile(bucketName, bucketPath);
                    if (!deleteSuccess) {
                        return ResponseResult.InternalServerError("Minio删除旧文件失败");
                    }

                    application.setRejectImage(null);
                }

                application.setRejectReason(null);
                System.out.println(application);
                applicationMapper.updateById(application);
                System.out.println("1111111111111111111111");
                return ResponseResult.success("审核成功");
            }
            else{
                return ResponseResult.InternalServerError("????????");
            }
        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }
    }

    @Override
    public ResponseResult<?> GetSelfApplication(Integer current, Integer size, NoticeSearchDTO searchDTO) {
        try{
            if (searchDTO.getTitle() != null && searchDTO.getTitle().isEmpty()){
                searchDTO.setTitle(null);
            }

            LambdaQueryWrapper<NoticeApplication> queryWrapper = Wrappers.lambdaQuery();

            if (searchDTO.getStatus() != null){
                queryWrapper.eq(NoticeApplication::getStatus, searchDTO.getStatus());
            }

            if (searchDTO.getTitle() != null){
                queryWrapper.like(NoticeApplication::getNoticeTitle,searchDTO.getTitle());
            }

            String Uid = StpUtil.getLoginId().toString();
            queryWrapper.eq(NoticeApplication::getUid,Uid);

            Page<NoticeApplication> page = new Page<>(current, size);
            Page<NoticeApplication> result = noticeApplicationMapper.selectPage(page, queryWrapper);



            return ResponseResult.success("查询成功",result.getTotal(),result.getRecords());

        }
        catch (Exception e){
            e.printStackTrace();
            return ResponseResult.InternalServerError(e.getMessage());
        }
    }

}
